#include "sysy_conf.h"
#include "sysy_lib.h"
#include "skiplist.h"
#include "dbg.h"

#include "gdsl/gdsl_types.h"
#include "gdsl/gdsl_hash.h"
#include "_strings.h"

#define SIZE 11

struct _my_struct
{
        int  integer;
        char*string;
};
typedef struct _my_struct* my_struct;

        static gdsl_element_t
my_struct_alloc (void* d)
{
        static int n = 0;

        my_struct e = (my_struct) malloc (sizeof (struct _my_struct));
        if (e == NULL)
        {
                return NULL;
        }

        e->integer = n++;
        e->string = strdup ((char*) d);

        return (gdsl_element_t) e;
}

        static void
my_struct_free (gdsl_element_t e)
{
        my_struct s = (my_struct) e;
        free (s->string);
        free (s);
}

        static void
my_struct_printf (gdsl_element_t e, FILE* file, gdsl_location_t location, void* d)
{
        my_struct s = (my_struct) e;
        fprintf (file, "%d:%s ", s->integer, s->string);
}

        const char*
my_struct_key (gdsl_element_t e)
{
        my_struct s = (my_struct) e;
        return s->string;
}

typedef uint64_t lba_t;

typedef struct {
        lba_t min;
        lba_t max;
        struct skiplist *slist;
} wbuf_t;

typedef struct {
        lba_t lba;
} wbuf_ent_t;

int lba_cmp(const void *key, const void *data) {
        lba_t lba = *(lba_t *)key;
        wbuf_ent_t *ent = (wbuf_ent_t *)data;

        printf("lba_cmp %llu ent %llu\n", (LLU)lba, (LLU)ent->lba);

        if (lba - ent->lba < 0)
                return -1;
        else if (lba - ent->lba > 0)
                return 1;

        return 0;
}

void test_skiplist() {
        int ret;
        struct skiplist *slist;
        wbuf_ent_t *ent;

        wbuf_t g_wbuf;

        g_wbuf.min = 0;
        g_wbuf.max = (unsigned long long)-1;

        ret = skiplist_create(lba_cmp, SKIPLIST_MAX_LEVEL, SKIPLIST_CHKSIZE_DEF,
                        &g_wbuf.min, &g_wbuf.max, &slist);

        for (int i=1; i < 10; i++) {
                ret = ymalloc((void **)&ent, sizeof(wbuf_ent_t));

                ent->lba = i;

                printf("%d %p lba %llu\n", i, ent, (LLU)ent->lba);

                skiplist_put(slist, &ent->lba, ent);

                // ret = skiplist_get(slist, (void *)&i, &ent);
                // YASSERT(ret == 0);
        }

        skiplist_destroy(slist);
}

void test_gdsl_hash() {
        int         choice;
        gdsl_hash_t ht;

        mtrace ();

        ht = gdsl_hash_alloc ("MY HASH TABLE", my_struct_alloc, my_struct_free, my_struct_key, NULL, SIZE);
        if (ht == NULL)
        {
                fprintf (stderr, "%s:%d: %s - gdsl_hash_alloc(): NULL",
                                __FILE__, __LINE__, __FUNCTION__);
                exit (EXIT_FAILURE);
        }

        do
        {
                printf ("\t\tMENU - HASH\n\n");
                printf ("\t1> Insert\n");
                printf ("\t2> Search\n");
                printf ("\t3> Remove\n");
                printf ("\t4> Display\n");
                printf ("\t5> Flush\n");
                printf ("\t6> Fill factor\n");
                printf ("\t7> Dump\n");
                printf ("\t8> XML display\n");
                printf ("\t0> Quit\n\n");
                printf ("\t\tYour choice: ");
                scanf ("%d", &choice);

                switch (choice)
                {
                        case 1:
                                {
                                        char nom[50];

                                        printf ("String: ");
                                        scanf ("%s", nom);

                                        if (gdsl_hash_insert (ht, (void*) nom) == NULL)
                                        {
                                                printf ("ERROR: Insert failed!\n");
                                        }
                                }
                                break;

                        case 2:
                                {
                                        char nom[50];
                                        gdsl_element_t e;

                                        printf ("String: ");
                                        scanf ("%s", nom);

                                        e = gdsl_hash_search (ht, nom);
                                        if (e == NULL)
                                        {
                                                printf ("String '%s' doesn't exist\n", nom);
                                        }
                                        else
                                        {
                                                printf ("String '%s' found\n", nom);
                                        }
                                }
                                break;

                        case 3:
                                {
                                        char nom[50];
                                        gdsl_element_t e;

                                        printf ("String: ");
                                        scanf ("%s", nom);

                                        e = gdsl_hash_remove (ht, nom);
                                        if (e == NULL)
                                        {
                                                printf ("String '%s' doesn't exist\n", nom);
                                        }
                                        else
                                        {
                                                free_string (e);
                                        }
                                }
                                break;

                        case 4:
                                gdsl_hash_write (ht, my_struct_printf, stdout, " ");
                                printf ("\n");
                                break;

                        case 5:
                                gdsl_hash_flush (ht);
                                break;

                        case 6:
                                printf ("Fill factor: %g\n", gdsl_hash_get_fill_factor (ht));
                                break;

                        case 7:
                                gdsl_hash_dump (ht, my_struct_printf, stdout, NULL);
                                break;

                        case 8:
                                gdsl_hash_write_xml (ht, my_struct_printf, stdout, NULL);
                                break;
                }
        }
        while (choice != 0);

        gdsl_hash_free (ht);

        exit (EXIT_SUCCESS);

}


int main(int argc, char *argv[]) {
        test_gdsl_hash();
        return 0;
}
